package com.gxgeek.calculator.engine;

import com.gxgeek.calculator.CellContainer;
import com.gxgeek.enums.RiskDataTypeEnum;
import com.gxgeek.model.HandlerDemisionArgs;
import com.gxgeek.model.CalculateRequest;
import com.gxgeek.model.Cell;
import com.gxgeek.model.Query;
import com.gxgeek.service.CacheService;
import com.gxgeek.service.DataService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * 串行 计算引擎
 * @author gaoxing
 * @create 2018-05-24 下午2:34
 */
@Component
@Slf4j
public class SerialEngine implements Engine{
    @Autowired
    private CellContainer cellContainer;
    @Autowired
    private CacheService cacheService;
    @Autowired
    private DataService dataService;
    @Override
    public void executeBatch(Query query, Set<CalculateRequest> requests) {
        //先从缓存取数据
        Map<String, Object> typeInfo = new HashMap<>();

        for (CalculateRequest task : requests) {
            //    其中一个是脚本名 两一个是 脚本参数
            Object result = null;
            HandlerDemisionArgs handlerDemisionArgs = handlerDemisionArgs(task.getKey());
            Cell cell = cellContainer.getCell(handlerDemisionArgs.getKey());
            String cacheKey = getCacheKey(query.getCacheNameSpace(), task.getKey());
            if (cell.isCache() && (result = cacheService.getValue(cacheKey)) !=null){
                    task.setResult(result);
                    continue;
            }
            //获取数据 防止重复 优化
            if (!typeInfo.containsKey(cell.getType())) {
                Object typeData = getTypeData(query, cell.getType());
                if (typeData == null) {
                    continue;
                }
                typeInfo.put(cell.getType(), typeData);
            }
            //计算脚本
            result = cell.getUnit()._run(typeInfo.get(cell.getType()),  handlerDemisionArgs.getArgs());
            if (cell.isCache()) {
                cacheKey = getCacheKey(query.getCacheNameSpace(), task.getKey());
                cacheService.storeValue(cacheKey, cell.getExpireTime(), result);
            }
            task.setResult(result);
        }
    }

    private Object getTypeData(Query query, String type) {
        RiskDataTypeEnum riskDataTypeEnum = RiskDataTypeEnum.valueOf(type);
        return dataService.getLastUserData(query.getUserId(), riskDataTypeEnum);
    }

    //从 params中的 dimension 中解析出 脚本的参数
    //  例子behavior_device_biz_order-100d-LOGIN
    private HandlerDemisionArgs handlerDemisionArgs(String dimension) {
        String[] keys = dimension.split("-");
        if (keys.length > 1) {
            return HandlerDemisionArgs.builder()
                    .key(keys[0])
                    .args(Arrays.asList(Arrays.copyOfRange(keys, 1, keys.length)))
                    .build();
        } else {
            return HandlerDemisionArgs.builder()
                    .key(keys[0])
                    .build();
        }
    }

    private String getCacheKey(String namespace, String key) {
        return namespace + ":" + key;
    }
}
